﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace SensorRWTool
{
    abstract class Sensor
    {

        public Sensor(string descc, int numm)
        {
            desc = descc;
            num = numm;

            //创建传感器属性
            form = new Form();
            //设置子窗口panel属性
            form.TopLevel = false;
            form.FormBorderStyle = FormBorderStyle.None;
            form.Dock = DockStyle.Fill;

            configadrrdata = new byte[8] { 0x01, 0x06, 0x00, 0x3e, 0x00, 0x01, 0x29, 0xc6 };
            configbaudrate = new byte[8] { 0x01, 0x06, 0x00, 0x3f, 0x00, 0x60, 0xb9, 0xee };
            autoscanarr = new byte[8] { 0xFF, 0x03, 0x00, 0x3e, 0x00, 0x02, 0xb0, 0x19 };
        }

        public byte[] GetModbusCrc16(byte[] bytes, int n)
        {
            byte crcRegister_H = 0xFF, crcRegister_L = 0xFF;// 预置一个值为 0xFFFF 的 16 位寄存器

            byte polynomialCode_H = 0xA0, polynomialCode_L = 0x01;// 多项式码 0xA001

            for (int i = 0; i < n; i++)
            {
                crcRegister_L = (byte)(crcRegister_L ^ bytes[i]);

                for (int j = 0; j < 8; j++)
                {
                    byte tempCRC_H = crcRegister_H;
                    byte tempCRC_L = crcRegister_L;

                    crcRegister_H = (byte)(crcRegister_H >> 1);
                    crcRegister_L = (byte)(crcRegister_L >> 1);
                    // 高位右移前最后 1 位应该是低位右移后的第 1 位：如果高位最后一位为 1 则低位右移后前面补 1
                    if ((tempCRC_H & 0x01) == 0x01)
                    {
                        crcRegister_L = (byte)(crcRegister_L | 0x80);
                    }

                    if ((tempCRC_L & 0x01) == 0x01)
                    {
                        crcRegister_H = (byte)(crcRegister_H ^ polynomialCode_H);
                        crcRegister_L = (byte)(crcRegister_L ^ polynomialCode_L);
                    }
                }
            }

            return new byte[] { crcRegister_L, crcRegister_H };
        }

        public String GetSensorDesc()
        {
            return desc;
        }

        abstract public void Display();
        abstract public void ClearData();

        public byte[] GetQuestData()
        {
            return data;
        }
        abstract public byte[] GetQueryFrame(int addr);
        public byte[] GetConfigAddrFrame(int descaddr, int srcaddr)
        {
            if (srcaddr == -1)
            {
                configadrrdata[0] = 0x01;
            }
            else
            {
                configadrrdata[0] = (byte)srcaddr;
            }
            byte addrlow = (byte)(descaddr & 0xff);
            byte addrhigh = (byte)((descaddr >> 8) & 0xff);
            configadrrdata[4] = addrhigh;
            configadrrdata[5] = addrlow;

            byte[] crc16 = GetModbusCrc16(configadrrdata, 6);
            configadrrdata[6] = crc16[0];
            configadrrdata[7] = crc16[1];

            int x = 0;
            for (; x < 8; x++)
            {
                Console.WriteLine(configadrrdata[x]);
            }
            return configadrrdata;
        }

        public byte[] GetConfigBaudRateFrame(int addr, int baudrate)
        {
            baudrate = baudrate/100;
            byte baudratelow = (byte)(baudrate & 0xff);
            byte baudratehigh = (byte)((baudrate >> 8) & 0xff);

            if (addr == -1)
            {
                configbaudrate[0] = 0x01;
            }
            else
            {
                configbaudrate[0] = (byte)addr;
            }
            configbaudrate[4] = baudratehigh;
            configbaudrate[5] = baudratelow;

            byte[] crc16 = GetModbusCrc16(configbaudrate, 6);
            byte crc16low = crc16[0];
            byte crc16high = crc16[1];

            configbaudrate[6] = crc16low;
            configbaudrate[7] = crc16high;
            return configbaudrate; 
        }

        public int ParseConfigBaudRateFrame(byte[] response)
        {
            if (response.Length != 8)
            {
                return -1;
            }
            if (response[1] == 0x06)
            {
                byte[] crc16 = GetModbusCrc16(response, 6);
                if (response[6] == crc16[0] && response[7] == crc16[1])
                {
                    return 0;
                }
                return -1;
            }
            return -1;
        }

        public int ParseConfigAddrFrame(byte[] response)
        {
            if (response.Length != 8)
            {
                return -1;
            }
            if (response[1] == 0x06)
            {
                byte[] crc16 = GetModbusCrc16(response, 6);
                if (response[6] == crc16[0] && response[7] == crc16[1])
                {
                    return 0;
                }
                return -1;
            }
            return -1;
        }

        public byte[] GetAutoScanFrame()
        {
            return autoscanarr;
        }

        public int[] ParseAutoScanFrame(byte[] response)
        {
            int[] ret = new int[2];
            if (response.Length != 9)
                return null;
            if (response[0] == 0xff && response[1] == 0x03
                && response[2] == 0x04)
            {
                int baudrate = (response[5] << 8) | (response[6]);
                baudrate *= 100;
                ret[0] = baudrate;
                int addr = (response[3] << 8) | (response[4]);
                ret[1] = addr;
                return ret;
            }
            return null;
        }
        abstract public bool ParseData(byte[] data);

        private int num;
        private string desc;
        private int sensorargus;
        public Form form;
        public byte[] data;
        public byte[] configadrrdata;
        public byte[] configbaudrate;
        public byte[] autoscanarr;
        public int responelen;

        public byte devaddr;             //设备地址码
        private byte fqcode;              //查询功能码
        private byte fscode;              //设置功能码
        private short crc16;             //校验码
        private short regstart;          //寄存器起始地址
    }
   
    //土壤温湿度类
    class EarthHumiture : Sensor
    {
        public EarthHumiture(string descc, int numm) : base(descc, numm)
        {
            data = new byte[8] { 0x01, 0x03, 0x00, 0x04, 0x00, 0x02, 0x85, 0xca };
            tempLabel = new System.Windows.Forms.Label();
            humidityLabel = new System.Windows.Forms.Label();
            tempTextBox = new System.Windows.Forms.TextBox();
            humidityTextBox = new System.Windows.Forms.TextBox();

            tempLabel.AutoSize = true;
            tempLabel.Location = new System.Drawing.Point(39, 53);
            tempLabel.Size = new System.Drawing.Size(62, 18);
            tempLabel.Name = "temp";
            tempLabel.TabIndex = 0;
            tempLabel.Text = "温度：";

            tempTextBox.Location = new System.Drawing.Point(107, 50);
            tempTextBox.Size = new System.Drawing.Size(100, 28);
            tempTextBox.Name = "tempBox";
            tempTextBox.ReadOnly = true;
            tempTextBox.TabIndex = 1;


            humidityLabel.AutoSize = true;
            humidityLabel.Location = new System.Drawing.Point(256, 53);
            humidityLabel.Name = "hum";
            humidityLabel.Size = new System.Drawing.Size(62, 18);
            humidityLabel.TabIndex = 2;
            humidityLabel.Text = "湿度：";

            humidityTextBox.Location = new System.Drawing.Point(345, 50);
            humidityTextBox.Name = "humidityBox";
            humidityTextBox.Size = new System.Drawing.Size(100, 28);
            humidityTextBox.ReadOnly = true;
            humidityTextBox.TabIndex = 3;

            this.form.Controls.Add(tempLabel);
            this.form.Controls.Add(humidityLabel);
            this.form.Controls.Add(tempTextBox);
            this.form.Controls.Add(humidityTextBox);

            temp = 0.0;
            humidity = 0.0;
            responelen = 9;
            devaddr = 0x01;

        }

        public override void Display()
        {
            tempTextBox.Text = temp.ToString() + "℃";
            humidityTextBox.Text = humidity.ToString() + "%RH";
            tempTextBox.Show();
            humidityTextBox.Show();
        }

        public new byte[] GetQuestData()
        {
            return data;
        }

        public override byte[] GetQueryFrame(int addr)
        {
            if ( addr != -1)
            {
                //指定地址
                data[0] = (byte)addr;
            }
            else
            {
                //默认地址0x01
                data[0] = 0x01;
            }

            byte[] crc16 = GetModbusCrc16(data, 6);
            data[6] = crc16[0];
            data[7] = crc16[1];
            return data;

        }

        public override void ClearData()
        {
            tempTextBox.Text = "";
            humidityTextBox.Text = "";
            humidity = 0.0;
            temp = 0.0;
        }


        public override bool ParseData(byte[] data)
        {
            if (data[1] != 0x03 ||
                data[2] != 0x04)
            {
                return false;
            }
            ushort ustemp = (ushort)(data[5] << 8 | data[6]);
            temp = ustemp / 10.0;
            ushort ushum = (ushort)((data[3] << 8) | data[4]);
            humidity = ushum / 10.0;
            return true;
        }

        private Label tempLabel;
        private Label humidityLabel;
        private TextBox tempTextBox;
        private TextBox humidityTextBox;
        private double temp;      //温度
        private double humidity; //湿度

    }
    
    //风速传感器类
    class WindSpeed : Sensor
    {
        public WindSpeed(string descc, int numm) : base(descc, numm)
        {
            data = new byte[8] { 0x01, 0x03, 0x00, 0x09, 0x00, 0x01, 0x54, 0x08 };
            windspeedLabel = new System.Windows.Forms.Label();
            windspeedTextBox = new System.Windows.Forms.TextBox();

            windspeedLabel.AutoSize = true;
            windspeedLabel.Location = new System.Drawing.Point(130, 53);
            windspeedLabel.Size = new System.Drawing.Size(62, 18);
            windspeedLabel.Name = "speed";
            windspeedLabel.TabIndex = 0;
            windspeedLabel.Text = "风速：";

            windspeedTextBox.Location = new System.Drawing.Point(197, 50);
            windspeedTextBox.Size = new System.Drawing.Size(100, 28);
            windspeedTextBox.Name = "windspeedBox";
            windspeedTextBox.ReadOnly = true;
            windspeedTextBox.TabIndex = 1;

            this.form.Controls.Add(windspeedLabel);
            this.form.Controls.Add(windspeedTextBox);

            windspeed = 0.0;
            responelen = 7;
            devaddr = 0x01;
        }
        public override void Display()
        {
            windspeedTextBox.Text = windspeed.ToString() + "m/s";
        }
        public override bool ParseData(byte[] data)
        {

            if (data[1] != 0x03 ||
                data[2] != 0x02)
            {
                return false;
            }
            ushort uwindspeed = (ushort)(data[3] << 8 | data[4]);
            windspeed = uwindspeed / 10.0;
            return true;
        }
        public override void ClearData()
        {
            windspeedTextBox.Text = "";
            windspeed = 0;
        }
        public override byte[] GetQueryFrame(int addr)
        {
            if (addr != -1)
            {
                //指定地址
                data[0] = (byte)addr;
            }
            else
            {
                //默认地址0x01
                data[0] = 0x01;
            }

            byte[] crc16 = GetModbusCrc16(data, 6);
            data[6] = crc16[0];
            data[7] = crc16[1];
            return data;
        }
        private Label windspeedLabel;
        private TextBox windspeedTextBox;
        private double windspeed;

    }
    
    //光照传感器类
    class Light : Sensor
    {
        public Light(string descc, int numm) : base(descc, numm)
        {
            data = new byte[8] { 0x01, 0x03, 0x00, 0x02, 0x00, 0x02, 0x65, 0xcb };
            LightLabel = new System.Windows.Forms.Label();
            LightTextBox = new System.Windows.Forms.TextBox();

            LightLabel.AutoSize = true;
            LightLabel.Location = new System.Drawing.Point(130, 53);
            LightLabel.Size = new System.Drawing.Size(62, 18);
            LightLabel.Name = "lightlabel";
            LightLabel.TabIndex = 0;
            LightLabel.Text = "光照度：";

            LightTextBox.Location = new System.Drawing.Point(197, 50);
            LightTextBox.Size = new System.Drawing.Size(100, 28);
            LightTextBox.Name = "windspeedBox";
            LightTextBox.ReadOnly = true;
            LightTextBox.TabIndex = 1;

            this.form.Controls.Add(LightLabel);
            this.form.Controls.Add(LightTextBox);

            light = 0.0;
            responelen = 9;
            devaddr = 0x01;

        }
        public override void Display()
        {
            LightTextBox.Text = light.ToString() + "Lux";

        }
        public override bool ParseData(byte[] data)
        {
            if (data[1] != 0x03 ||
                 data[2] != 0x04)
            {
                return false;
            }
            uint u32light = (ushort)(data[3] << 24 | data[4] << 16 | data[5] << 8 | data[6]);
            light = u32light / 10.0;
            return true;
        }
        public override void ClearData()
        {
            LightTextBox.Text = "";
            light = 0.0;
        }
        public override byte[] GetQueryFrame(int addr)
        {
            if (addr != -1)
            {
                //指定地址
                data[0] = (byte)addr;
            }
            else
            {
                //默认地址0x01
                data[0] = 0x01;
            }

            byte[] crc16 = GetModbusCrc16(data, 6);
            data[6] = crc16[0];
            data[7] = crc16[1];
            return data;
        }

        private Label   LightLabel;
        private TextBox LightTextBox;
        private double light;
    }

}
